/**
 * @author <a href = "mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a>
 * Creaci&oacute;n: 10-nov-2005 - 18:26:16
 * Cambios :
 *  Autor  |  Cambios
 *
 */

package com.psiqueware.alheli.dao.logger;

import com.psiqueware.alheli.dao.EnlaceTransaccional;
import com.psiqueware.alheli.dao.hibernate.HibernateServiceLocator;
import com.psiqueware.alheli.dao.logger.dao.LoggingDAOFactory;
import com.psiqueware.alheli.logging.Logger;
import com.psiqueware.alheli.logging.LoggerFactory;
import com.psiqueware.alheli.logging.log4j.LogMessage;
import com.psiqueware.alheli.logging.log4j.LogThrowable;
import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;


/**
 * Appender utilizado para logear los logs de Log4j a base de datos.
 * <br/>Paquete Original: com.psiqueware.basico.logging
 * <br/>Nombre  Original: DataBaseAppender
 * <br/><a href="DataBaseAppender.java.html"><i>Ver Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a>
 * @version Revision: 1.1 10-nov-2005 18:26:16
 * @noinspection ClassWithoutToString, ClassWithoutLogger
 */
public final class DataBaseAppender extends AppenderSkeleton implements Appender
{

    /**
     * Log para esta clase.
     */
    private static final Logger log = LoggerFactory.getLogger(DataBaseAppender.class);

    /**
     * Construye un DataBaseAppender
     */
    public DataBaseAppender()
    {
    }

    /**
     * (no-javadoc)
     *
     * @param loggingEvent
     *
     * @see Appender#doAppend(org.apache.log4j.spi.LoggingEvent)
     */
    protected void append(LoggingEvent loggingEvent)
    {
        final EnlaceTransaccional enlaceTransaccional = LoggingDAOFactory.nuevoEnlace();
        enlaceTransaccional.iniciaTransaccion();
        if (isEventoLogeable(loggingEvent))
        {
            LogMessage logMessage = new LogMessage(loggingEvent);
            try
            {
                //Guardamos los throwables
                ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation();
                if (null != throwableInformation)
                {
                    String[] info = throwableInformation.getThrowableStrRep();
                    for (int i = 0; i < info.length; i++)
                    {
                        String s = info[i];
                        LogThrowable logThrowable = new LogThrowable(s, new Integer(i));
                        logThrowable = LoggingDAOFactory.findDAOLogThrowable(enlaceTransaccional).saveLogThrowable(logThrowable, enlaceTransaccional);
                        logMessage.addLogThrowable(logThrowable);
                    }
                }

                //Guardamos el mensaje
                LoggingDAOFactory.findDAOLogMessage(enlaceTransaccional).saveLogMessage(logMessage, enlaceTransaccional);
            }
            catch (Exception e)
            {
                enlaceTransaccional.rollBack();
                String error = "No se pudo persistir el evento de log.";
                this.close();
                log.error(error);
                log.error(e);
            }
            enlaceTransaccional.finalizaTransaccion();
        }
    }

    private boolean isEventoLogeable(LoggingEvent loggingEvent)
    {
        //Verificamos que no se haya cerrado el Appender.
        boolean activo = true;
        //La fabrica de sesiones debe estar abierta.
        boolean fabricaSessionCreada = HibernateServiceLocator.isSessionFactoryCreated();
        //La sesi&oacute;n debe estar creada.
        boolean sessionCreada = HibernateServiceLocator.getSession() != null;
        //Verificamos que no sea un log de HBM
        boolean noEsUnEventoHBM = !loggingEvent.getLoggerName().startsWith("org.hibernate.");
        return activo && fabricaSessionCreada && sessionCreada && noEsUnEventoHBM;
        //return false;
    }

    /**
     * El layout lo determinar&aacute; la base de datos.
     *
     * @return false en todos los casos.
     */
    public boolean requiresLayout()
    {
        return false;
    }

    /**
     * Cierra este appender.
     */
    public void close()
    {

    }

    /**
     * Nos dice si el appender se encuentra cerrado.
     *
     * @noinspection BooleanMethodNameMustStartWithQuestion
     */
    protected boolean closed()
    {
        return true;
    }


}
